package se.energimyndigheten.lampguiden.bulbreplacement;

import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.AssetManager;
import android.preference.PreferenceManager;
import android.util.Log;

import org.json.JSONException;

import se.energimyndigheten.lampguiden.LightSource;
import se.energimyndigheten.lampguiden.util.AssetsUtil;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Map;

public class ComparsionCalculator {
    private int mBaseLife;
    private double mBasePrice;
    private int mBasePower;
    private LightSource[] mLightSources;
    private LightSource mBaseLightSource;
    private Map<Integer, String> mConversionTable;
    private double usedEnergyNormalized;
    private double usedEnergyCost;
    private double lampsCost;
    private static SharedPreferences mPreferences;
    private int lumen;
    
    public static ComparsionCalculator initiateCalculator(Context ctx, LightSource baseLight, int basePower, Map<Integer, String> conversionTable) throws JSONException,
            IOException {
        AssetManager am = ctx.getAssets();
        ComparsionCalculator cc = AssetsUtil.initComparsionCalculatorFromJson(AssetsUtil.getFileContents(
                am,
                AssetsUtil.JSON_PATH_CALCULATIONS));
        cc.setConversionTable(conversionTable);
        cc.setBaseLight(baseLight);
        cc.setBasePower(basePower);
        cc.setContext(ctx);
        return cc;
    }

    private void setContext(Context ctx) {
        mPreferences = PreferenceManager.getDefaultSharedPreferences(ctx);
    }

    public ComparsionCalculator(int baseLifeExpetancy, double baseElectricityPrice, LightSource[] comparableLights) {
        mBaseLife = baseLifeExpetancy;
        mBasePrice = baseElectricityPrice;
        mLightSources = comparableLights;
    }
    
    private LightSource getLightSourceByType(String type) {
        for(LightSource src : mLightSources) {
            if (type.equals(src.getType()))
                return src;
        }
        return null;
    }

    /** Figure out suitable lamps and prepare for comparisons */
    public LightSource[] getLightSources() {
         // Turn the dummy source into a the fullblown version 
         LightSource base = getLightSourceByType(mBaseLightSource.getLampType());
         
         // Prepare
         // Find substitutes
         String range = mConversionTable.get(mBasePower); 
         lumen = getMaxOfRange(range); // Use the lumen max value for calculation
         double baseLife = base.getLifeExpetancy();
         double basePrice = base.getPrice(lumen);
         double basePowerNeeded = base.getPower();

         double lampsNeeded = mBaseLife / baseLife;
         lampsCost = lampsNeeded * basePrice;
         
         double usedEnergy = mBasePower / 1000.0 * mBaseLife;
         usedEnergyCost = usedEnergy * mBasePrice;
         usedEnergyNormalized = usedEnergy / basePowerNeeded;

         // Look through all the known lights
         ArrayList<LightSource> res = new ArrayList<LightSource>();
         for(LightSource candidate : mLightSources) {
             if (lumen < candidate.getMaxLumen() // Strong enough
                     && base.hasReplacement(candidate.getType())) { // Possible
                 int price = candidate.getPrice(lumen); 
                 candidate.setMyPrice(loadPrice(candidate, price)); 
                 candidate.setMySavings(getCostComparsion(candidate, price)); 
                 res.add(candidate);
             }
         }
         // Sort result
         Collections.sort(res, new LightComparator());

         // Pack them:
         LightSource[] result = new LightSource[res.size()]; 
         for(int i=0; i<res.size(); i++) 
             result[i]=res.get(i);
         return result;
    }
    
    // For list sorting
    public class LightComparator implements Comparator<LightSource> {
        @Override
        public int compare(LightSource o1, LightSource o2) {
            return o1.getEnergyRank() - o2.getEnergyRank();
        }
    }
    
    /*** Calculate savings from using a certain light source compared to other
     * 
     * @param index light source that will be compared to mBaseLightSource
     * @return savings using the light source at index */
    public int getCostComparsion(LightSource light, int price) {

        if (price == -1) {
            price = light.getPrice(lumen);
        }
        int lifeExpectancy = light.getLifeExpetancy();
        double powerNeed = light.getEffiency();

        double lampsNeeded = mBaseLife / (double)lifeExpectancy;
        double lampsPurchaseCost = lampsNeeded * price;
        
        // lumen/watt depends on light source type (efficency)
        double usedEnergy = usedEnergyNormalized * powerNeed;
        double thisUsedEnergyCost = usedEnergy * mBasePrice;
        
        double totalSaving = lampsCost + usedEnergyCost - lampsPurchaseCost - thisUsedEnergyCost;
        double perLampSaving = totalSaving / lampsNeeded;
        return (int) Math.round(perLampSaving/5)*5;
    }

    // Range is currently stored as a string with comma separated integers
    private int getMaxOfRange(String range) {
        int comma = range.lastIndexOf(",");
        if (comma==-1)
            return -1;
        String val = range.substring(comma+1);
        return Integer.parseInt(val);
    }

    public void setBaseLight(LightSource baseLight) {
        mBaseLightSource = baseLight;
    }

    private void setBasePower(int basePower) {
        mBasePower = basePower;
    }
    
    private void setConversionTable(Map<Integer, String> conversionTable) {
        mConversionTable = conversionTable;
    }

    private String getSaveRef(LightSource light) {
        String saveRef = "MyPrice."+mBasePower+"."+light.getName();
        Log.d("MyPrice", saveRef);
        return saveRef;
    }
    
    public int loadPrice(LightSource light, int fallback) {
        return mPreferences.getInt(getSaveRef(light), fallback);
    }

    public void savePrice(int price, LightSource light) {
        SharedPreferences.Editor editor = mPreferences.edit();
        editor.putInt(getSaveRef(light), price);
        editor.commit();
    }
}